/*
 * LoRa.c
 *
 *  Created on: May 30, 2020
 *      Author: gary
 */
#include <stdio.h>
#include "LoRa.h"

LoRaSettingsTyprdef LoRaSettings;

// LoRa software driver
uint8_t LoRa_init(uint32_t frequency, uint8_t boost)
{
  // setup pins
  // perform reset
  HAL_GPIO_WritePin(LoRa_RST_GPIO_Port, LoRa_RST_Pin, GPIO_PIN_RESET);
  HAL_Delay(20);
  HAL_GPIO_WritePin(LoRa_RST_GPIO_Port, LoRa_RST_Pin, GPIO_PIN_SET);
  HAL_Delay(50);
  // check version
  uint8_t version = LoRa_readRegister(REG_VERSION);
  if(version != 0x12)
  {
    return 1;
  }
  // put in sleep mode
  LoRa_sleep();
  // set frequency
  LoRa_setFrequency(frequency);
  // set base addresses
  LoRa_writeRegister(REG_FIFO_TX_BASE_ADDR, 0);
  LoRa_writeRegister(REG_FIFO_RX_BASE_ADDR, 0);
  // set LNA boost
  LoRa_writeRegister(REG_LNA, LoRa_readRegister(REG_LNA) | 0x03);
  // set auto AGC
  LoRa_writeRegister(REG_MODEM_CONFIG_3, 0x04);
  if(boost)
  {
  	// set output power to 20 dBm
    LoRa_setTxPower(17, PA_OUTPUT_PA_BOOST_PIN);
  }
  else
  {
    LoRa_setTxPower(14, PA_OUTPUT_RFO_PIN);
  }
  //setTxPowerMax(14);  //PA_BOOST
  // set Spreading Factor to 7 (6~12)
  LoRa_setSpreadingFactor(10);
  // put in standby mode
  LoRa_setSignalBandwidth(125E3);
  LoRa_setCodingRate(6);
  LoRa_setSyncWord(100);
  LoRa_disableCrc();
  LoRa_enableCrc();
  LoRa_idle();
  return 0;
}

void LoRa_lowDataRateOptimize(uint8_t status)
{
	if(status)
	{
		LoRa_writeRegister(REG_MODEM_CONFIG_3, LoRa_readRegister(REG_MODEM_CONFIG_3) | 0x08);
	}
	else
	{
		LoRa_writeRegister(REG_MODEM_CONFIG_3, LoRa_readRegister(REG_MODEM_CONFIG_3) & 0xf7);
	}
}

void LoRa_end()
{
	LoRa_sleep();
}

void LoRa_beginPacket(uint8_t implicitHeader)
{
  // put in standby mode
	LoRa_idle();
  if (implicitHeader)
  {
  	LoRa_implicitHeaderMode();
  } else
  {
  	LoRa_explicitHeaderMode();
  }
  // reset FIFO address and paload length
  LoRa_writeRegister(REG_FIFO_ADDR_PTR, 0);
  LoRa_writeRegister(REG_PAYLOAD_LENGTH, 0);
}

void LoRa_endPacket()
{
  // put in TX mode
  LoRa_writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX);
  // wait for TX done
  while((LoRa_readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0)
  {
  	HAL_Delay(100);
  }
  // clear IRQ's
  LoRa_writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
}

uint8_t LoRa_parsePacket(uint8_t size)
{
  int packetLength = 0;
  int irqFlags = LoRa_readRegister(REG_IRQ_FLAGS);

  if (size > 0)
  {
  	LoRa_implicitHeaderMode();
    LoRa_writeRegister(REG_PAYLOAD_LENGTH, size & 0xff);
  }
  else
  {
  	LoRa_explicitHeaderMode();
  }

  // clear IRQ's
  LoRa_writeRegister(REG_IRQ_FLAGS, irqFlags);

  if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0)
  {
    // received a packet
    LoRaSettings.packetIndex = 0;
    // read packet length
    if (LoRaSettings.implicitHeaderMode)
    {
      packetLength = LoRa_readRegister(REG_PAYLOAD_LENGTH);
    }
    else
    {
      packetLength = LoRa_readRegister(REG_RX_NB_BYTES);
    }
    // set FIFO address to current RX address
    LoRa_writeRegister(REG_FIFO_ADDR_PTR, LoRa_readRegister(REG_FIFO_RX_CURRENT_ADDR));
    // put in standby mode
    LoRa_idle();
  }
  else if (LoRa_readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE))
  {
    // not currently in RX mode
    // reset FIFO address
    LoRa_writeRegister(REG_FIFO_ADDR_PTR, 0);
    // put in single RX mode
    LoRa_writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE);
  }
  return packetLength;
}

uint8_t LoRa_packetRssi()
{
	return (LoRa_readRegister(REG_PKT_RSSI_VALUE) - (LoRaSettings.frequency < 868E6 ? 164 : 157));
}

uint8_t LoRa_packetSnr()
{
	return LoRa_readRegister(REG_PKT_SNR_VALUE) >> 2;
}

uint8_t LoRa_writeFifoByte(uint8_t data)
{
	int currentLength = LoRa_readRegister(REG_PAYLOAD_LENGTH);
	// check size
	if (currentLength == MAX_PKT_LENGTH)
	{
		return 1;
	}
	// write data
	LoRa_writeRegister(REG_FIFO, data);
	// update length
	LoRa_writeRegister(REG_PAYLOAD_LENGTH, currentLength + 1);
	return 0;
}

uint8_t LoRa_writeFifoBytes(const uint8_t *buffer, uint8_t size)
{
  int currentLength = LoRa_readRegister(REG_PAYLOAD_LENGTH);
  // check size
  if ((currentLength + size) > MAX_PKT_LENGTH)
  {
    size = MAX_PKT_LENGTH - currentLength;
  }
  // write data
  for (size_t i = 0; i < size; i++)
  {
    LoRa_writeRegister(REG_FIFO, buffer[i]);
  }
  // update length
  LoRa_writeRegister(REG_PAYLOAD_LENGTH, currentLength + size);
  return size;
}

uint8_t LoRa_available()
{
	return (LoRa_readRegister(REG_RX_NB_BYTES) - LoRaSettings.packetIndex);
}

uint8_t LoRa_readFifo()
{
	if (!LoRa_available())
	{
		return -1;
	}
	LoRaSettings.packetIndex++;
	return LoRa_readRegister(REG_FIFO);
}

uint8_t LoRa_peek()
{
  if (!LoRa_available())
  {
  	return -1;
	}
  // store current FIFO address
  int currentAddress = LoRa_readRegister(REG_FIFO_ADDR_PTR);
  // read
  uint8_t b = LoRa_readRegister(REG_FIFO);
  // restore FIFO address
  LoRa_writeRegister(REG_FIFO_ADDR_PTR, currentAddress);
  return b;
}

//void LoRa_onReceive()  //Don't know the meaning for now
//{
//	LoRa_writeRegister(REG_DIO_MAPPING_1, 0x00);
//}

void LoRa_receive(uint8_t size)
{
  LoRa_writeRegister(REG_DIO_MAPPING_1, 0x00);
  if (size > 0)
  {
  	LoRa_implicitHeaderMode();
    LoRa_writeRegister(REG_PAYLOAD_LENGTH, size & 0xff);
  }
  else
  {
  	LoRa_explicitHeaderMode();
  }

  LoRa_writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS);
}

void LoRa_idle()
{
	LoRa_writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY);
}

void LoRa_sleep()
{
	LoRa_writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP);
}

void LoRa_setTxPower(uint8_t level, uint8_t outputPin)
{
  if (PA_OUTPUT_RFO_PIN == outputPin)
  {
    // RFO
    if (level < -1)
    {
    	level = -1;
    }
    else if (level > 14)
    {
    	level = 14;
    }
		LoRa_writeRegister(REG_PaDac,0x84);
		LoRa_writeRegister(REG_PA_CONFIG, RFO | (level + 1));
  }

  else {			// PA BOOST
    if (level < 2)
    {
    	level = 2;
    }
    else if (level > 17)
    {
    	level = 17;
    }
		LoRa_writeRegister(REG_PaDac,0x87);
		LoRa_writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2));//LoRa_writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2))
  }
}

void LoRa_setTxPowerMax(uint8_t level)
{
	if (level < 5)
	{
		level = 5;
	}
	else if(level > 20)
	{
		level = 20;
	}
	LoRa_writeRegister(REG_LR_OCP,0x3f);
	LoRa_writeRegister(REG_PaDac,0x87);//Open PA_BOOST
	LoRa_writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 5));
}

void LoRa_setFrequency(uint32_t frequency)
{
  LoRaSettings.frequency = frequency;
  uint64_t frf = ((uint64_t)frequency << 19) / 32000000;
  LoRa_writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16));
  LoRa_writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8));
  LoRa_writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0));
}

void LoRa_setSpreadingFactor(uint8_t sf)
{
  if (sf < 6)
  {
  	sf = 6;
	}
  else if (sf > 12)
  {
  	sf = 12;
  }
  if (sf == 6)
  {
    LoRa_writeRegister(REG_DETECTION_OPTIMIZE, 0xc5);
    LoRa_writeRegister(REG_DETECTION_THRESHOLD, 0x0c);
  }
  else
  {
    LoRa_writeRegister(REG_DETECTION_OPTIMIZE, 0xc3);
    LoRa_writeRegister(REG_DETECTION_THRESHOLD, 0x0a);
  }
  LoRa_writeRegister(REG_MODEM_CONFIG_2, (LoRa_readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0));
}

void LoRa_setSignalBandwidth(uint32_t sbw)
{
  uint8_t bw;

  if (sbw <= 7.8E3) { bw = 0; }
  else if (sbw <= 10.4E3) 	{ bw = 1; }
  else if (sbw <= 15.6E3) 	{ bw = 2; }
  else if (sbw <= 20.8E3) 	{ bw = 3; }
  else if (sbw <= 31.25E3)	{ bw = 4; }
  else if (sbw <= 41.7E3)		{ bw = 5; }
  else if (sbw <= 62.5E3) 	{ bw = 6; }
  else if (sbw <= 125E3)		{ bw = 7; }
  else if (sbw <= 250E3)		{ bw = 8; }
  else 											{ bw = 9; }
  LoRa_writeRegister(REG_MODEM_CONFIG_1,(LoRa_readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4));
}

void LoRa_setCodingRate(uint8_t denominator)
{
  if (denominator < 5) {
    denominator = 5;
  } else if (denominator > 8) {
    denominator = 8;
  }
  int cr = denominator - 4;
  LoRa_writeRegister(REG_MODEM_CONFIG_1, (LoRa_readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1));
}

void LoRa_setPreambleLength(uint16_t length)
{
	LoRa_writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8));
	LoRa_writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0));
}

void LoRa_setSyncWord(uint8_t sw)
{
	LoRa_writeRegister(REG_SYNC_WORD, sw);
}

void LoRa_enableCrc()
{
	LoRa_writeRegister(REG_MODEM_CONFIG_2, LoRa_readRegister(REG_MODEM_CONFIG_2) | 0x04);
}

void LoRa_disableCrc()
{
	LoRa_writeRegister(REG_MODEM_CONFIG_2, LoRa_readRegister(REG_MODEM_CONFIG_2) & 0xfb);
}

uint8_t LoRa_random()
{
	return LoRa_readRegister(REG_RSSI_WIDEBAND);
}

void LoRa_dumpRegisters()
{
	for(uint8_t i=0; i<128; i++)
	{
		printf("0x%02x: 0x%02x", i, LoRa_readRegister(i));
	}
}

void LoRa_explicitHeaderMode()
{
	LoRaSettings.implicitHeaderMode = 0;
	LoRa_writeRegister(REG_MODEM_CONFIG_1, LoRa_readRegister(REG_MODEM_CONFIG_1) & 0xfe);
}

void LoRa_implicitHeaderMode()
{
	LoRaSettings.implicitHeaderMode = 1;
	LoRa_writeRegister(REG_MODEM_CONFIG_1, LoRa_readRegister(REG_MODEM_CONFIG_1) | 0x01);
}
/**************************************************/



// LoRa DIO0 rising edge interrupt callback function (accept interrupt)
__weak void onReceiveCallback(uint8_t packetLength)
{
	printf("onReceiveCallback run packetLength:%d\n", packetLength);
}

void LoRa_handleDio0Rise()
{
	printf("LoRa_handleDio0Rise");
	uint8_t irqFlags = LoRa_readRegister(REG_IRQ_FLAGS);
	// clear IRQ's
	LoRa_writeRegister(REG_IRQ_FLAGS, irqFlags);
	if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0)
	{
		// received a packet
		LoRaSettings.packetIndex = 0;
		// read packet length
		int packetLength = LoRaSettings.implicitHeaderMode ? LoRa_readRegister(REG_PAYLOAD_LENGTH) : LoRa_readRegister(REG_RX_NB_BYTES);
		// set FIFO address to current RX address
		LoRa_writeRegister(REG_FIFO_ADDR_PTR, LoRa_readRegister(REG_FIFO_RX_CURRENT_ADDR));
		onReceiveCallback(packetLength);
		// reset FIFO address
		LoRa_writeRegister(REG_FIFO_ADDR_PTR, 0);
	}
}

void LoRa_handleDio1Rise()
{
	uint8_t irqFlags = LoRa_readRegister(REG_IRQ_FLAGS);
	LoRa_writeRegister(REG_IRQ_FLAGS, irqFlags);
	LoRa_writeRegister(REG_FIFO_ADDR_PTR, 0);
}

/**************************************************/
